package com.demo.date.utils;

import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.TimeZone;

/**
 * @author jay
 * @date 2019/4/10 11:26
 */
public final class DateTimeUtils {

    public static final String SHANGHAI_ZONE_ID = "Asia/Shanghai";
    public static final String PARTTERN = "yyyy-MM-dd HH:mm:ss";

    private DateTimeUtils() {

    }

    public static LocalDate nowDate() {
        return LocalDate.now();
    }

    public static LocalDateTime nowDateTime() {
        return LocalDateTime.now(ZoneId.of(SHANGHAI_ZONE_ID));
    }

    public static LocalDate dateTime2Date(LocalDateTime nowTime) {
        return nowTime.toLocalDate();
    }


    public static int toDayOfWeek(LocalDateTime nowTime) {
        DayOfWeek dayOfWeek = nowTime.getDayOfWeek();
        return dayOfWeek.getValue();
    }

    public static boolean isDual(LocalDateTime nowTime) {
        String str = nowTime.toLocalDate().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        return Integer.valueOf(str) % 2 == 0;
    }

    public static LocalTime toTime(LocalDateTime nowTime) {
        return nowTime.toLocalTime();
    }


    /**
     * 07:00 字符串转localTIme
     *
     * @param begin
     * @return
     */
    public static LocalTime toTime(String begin) {
        return LocalTime.parse(begin, DateTimeFormatter.ofPattern("HH:mm"));
    }

    public static String millsToString(long currentTime) {
        LocalDateTime localDateTime = Instant.ofEpochMilli(currentTime).atZone(ZoneId.systemDefault()).toLocalDateTime();
        return localDateTime.format(DateTimeFormatter.ofPattern(PARTTERN));
    }

    public static String millsToString(long currentTime, String pattern) {
        LocalDateTime localDateTime = Instant.ofEpochMilli(currentTime).atZone(ZoneId.systemDefault()).toLocalDateTime();
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDateTime millsToLocalDate(long mills) {
        return Instant.ofEpochMilli(mills).atZone(ZoneId.of(SHANGHAI_ZONE_ID)).toLocalDateTime();
    }

    public static String nowStr() {
        return DateTimeUtils.nowDateTime().format(DateTimeFormatter.ofPattern(PARTTERN));
    }

    public static LocalDateTime parseStr2DateTime(String str) {
        return LocalDateTime.parse(str, DateTimeFormatter.ofPattern(PARTTERN));
    }

    public static String format(String time) {
        LocalDateTime localDateTime = LocalDateTime.parse(time, DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        return localDateTime.format(DateTimeFormatter.ofPattern(PARTTERN));
    }

    public static String utcTimeFormat() {
        return LocalDateTime.now(TimeZone.getTimeZone("Etc/GMT").toZoneId())
                .format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
    }

    public static Long time2Mills(LocalDateTime updateTime) {
        return updateTime.atZone(ZoneId.of(SHANGHAI_ZONE_ID)).toInstant().toEpochMilli();
    }

    public static long nowMills() {
        return nowDateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }


    public static boolean isAfter(LocalDateTime createTime, LocalDateTime now, long dual) {
        Duration between = Duration.between(createTime, now);
        long seconds = between.getSeconds();
        return seconds >= dual;
    }

    public static String date2Str(LocalDateTime date) {
        return date.format(DateTimeFormatter.ofPattern(PARTTERN));
    }

    public static LocalDateTime beginOfDay() {
        return nowDate().atStartOfDay();
    }

    public static LocalDateTime beginOfDay(LocalDateTime start) {
        return start.toLocalDate().atStartOfDay();
    }

    public static LocalTime parseStr2Time(String source) {

        return LocalTime.parse(source, DateTimeFormatter.ofPattern("HH:mm:ss"));
    }

    public static LocalDate parseStr2Date(String source) {
        if (StringUtils.isEmpty(source)) {
            return null;
        }
        LocalDate localDate = null;
        try {
            localDate = LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        } catch (Exception e) {
            localDate = LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        }
        return localDate;
    }

    public static LocalDateTime firstDayOfCurrentMonth() {
        LocalDateTime now = nowDateTime();

        return now.with(TemporalAdjusters.firstDayOfMonth()).toLocalDate().atStartOfDay();
    }

    public static LocalDateTime endDayOfCurrentMonth() {
        LocalDateTime now = nowDateTime();
        return now.with(TemporalAdjusters.lastDayOfMonth()).toLocalDate().atStartOfDay();

    }

    public static String endDayOfDate(String date) {
        LocalDate localDate = parseStr2Date(date);
        return localDate.with(TemporalAdjusters.lastDayOfMonth()).toString();
    }

    public static String date2Str(LocalDate localDate) {
        return localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    public static Long getCurrentMonthDays() {
        LocalDateTime begin = endDayOfCurrentMonth();
        LocalDateTime end = firstDayOfCurrentMonth();
        return end.until(begin, ChronoUnit.DAYS) + 1;
    }

    public static LocalDate lastDayOfMonth(LocalDate date) {
        return date.with(TemporalAdjusters.lastDayOfMonth());
    }

    public static LocalDate firstDayOfMonth(LocalDate date) {
        return date.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 获取当前时间的前一天
     *
     * @return
     */
    public static LocalDateTime beforeDateTime() {
        LocalDateTime now = nowDateTime();
        LocalDateTime beforeDateTime = now.plus(-1, ChronoUnit.DAYS);
        return beforeDateTime;
    }

    /**
     * 获取当前时间的前一天
     *
     * @return
     */
    public static String beforeDate() {
        LocalDate now = nowDate();
        LocalDate beforeDate = now.plus(-1, ChronoUnit.DAYS);
        return beforeDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    }

    public static LocalDateTime date2LocalDateTime(Date date) {
        LocalDateTime localDateTime = null;
        if (date != null) {
            localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        }
        return localDateTime;
    }


    public static LocalDate endDayOfLastMonth() {
        return nowDate().minusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
    }


    public static Date plusDate(Date start, int days) {
        if (Objects.isNull(start)) {
            return null;
        }
        LocalDateTime localDateTime = date2LocalDateTime(start);
        LocalDateTime time = localDateTime.plusDays(days);
        return new Date(time2Mills(time));
    }

    public static String date2Str(Date date) {
        if (null == date) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return format.format(date);
    }

    public static String date2Str(Date date, String format) {
        if (null == date) {
            return null;
        }
        return new SimpleDateFormat(format).format(date);
    }

    public static Date addYears(Date date, int step) {
        LocalDateTime localDateTime = DateTimeUtils.date2LocalDateTime(date);
        return localDate2Date(localDateTime.plusYears(step).toLocalDate());
    }

    public static Date localDate2Date(LocalDate localDate) {
        if (Objects.isNull(localDate)) {
            return null;
        }
        Instant instant = localDate.atStartOfDay().atZone(ZoneId.of("Asia/Shanghai")).toInstant();
        return Date.from(instant);
    }

    public static Date localDate2Date(LocalDateTime localDateTime) {
        if (Objects.isNull(localDateTime)) {
            return null;
        }
        return Date.from(localDateTime.atZone(ZoneId.of("Asia/Shanghai")).toInstant());
    }

    public static Date getStartTime(Date date) {
        Calendar dateStart = Calendar.getInstance();
        dateStart.setTime(date);
        dateStart.set(Calendar.HOUR_OF_DAY, 0);
        dateStart.set(Calendar.MINUTE, 0);
        dateStart.set(Calendar.SECOND, 0);
        return dateStart.getTime();
    }

    public static Date getEndTime(Date date) {
        Calendar dateStart = Calendar.getInstance();
        dateStart.setTime(date);
        dateStart.set(Calendar.HOUR_OF_DAY, 23);
        dateStart.set(Calendar.MINUTE, 59);
        dateStart.set(Calendar.SECOND, 59);
        return dateStart.getTime();
    }

    public static Integer getNowYear() {
        return nowDate().getYear();
    }

    public static Date idCard2BirthDay(String idCardCode) {
        if (StringUtils.isEmpty(idCardCode) || idCardCode.length() < 14) {
            return null;
        }
        String birthStr = idCardCode.substring(6, 14);
        try {
            return localDate2Date(parseStr2Date(birthStr, "yyyyMMdd"));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static LocalDate parseStr2Date(String dateStr, String format) {
        return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(format));
    }

    public static boolean isAfter(Date target, Date source) {
        if (Objects.isNull(source) || Objects.isNull(target)) {
            return false;
        }
        return source.compareTo(target) > 0;
    }
}
